home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 …SCII & the Runetime Code / ADC Developer CD (1992-07) (''Butch ASCII And The Runtime Code'')_iso / Dev.CD 199207.iso / Tools & Apps / OS⁄Toolbox / Apple Events / AE Word Services 1.0d6 / Writeswell Jr. Source / ServiceMgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-23  |  9.3 KB  |  418 lines  |  [TEXT/KAHL]

  1. /* ServiceMgr.c
  2.  * Handle the Services menu in Writeswell, Jr.
  3.  * ©1992 Working Software, Inc.
  4.  * This source code is copyrighted.  Permission is granted to use the Word Services
  5.  * portion of the Writeswell Jr. source code in your own programs, but you 
  6.  * may not distribute the Writeswell Jr. word-processor code as a 
  7.  * commercial product.  If you modify the code, please do not call it 
  8.  * Writeswell Jr. (or Writeswell.)  This will ensure that people understand the 
  9.  * program and don’t have to deal with a number of different versions with 
  10.  * who-knows-what going on in the code.
  11.  * 
  12.  * Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
  13.  * 19 Apr 92 Mike Crawford
  14.  */
  15.  
  16. #include <Aliases.h>
  17. #include <EPPC.h>
  18. #include <AppleEvents.h>
  19. #include <AEObjects.h>
  20. #include <AEPackObject.h>
  21. #include "AERegistry.h"
  22. #include "WordServices.h"
  23. #include "TestBed.h"
  24. #include "TBConstants.h"
  25. #include "AppEvents.h"
  26. #include "AEObj.h"
  27. #include "Gripe.h"
  28. #include "Prefs.h"
  29. #include "DoChecking.h"
  30. #include "ObText.h"
  31. #include "InitMenu.h"
  32. #include "ServiceMgr.h"
  33. #include "TBGlobals.h"
  34.  
  35. OSErr GetNewBatchService( void )
  36. {
  37.     AEAddressDesc    spellerAddr;
  38.     AEDesc            stringDesc;
  39.     AEDesc            aliasDesc;
  40.     OSErr            err;
  41.     
  42.     if ( CountServices() >= kMaxServices ){
  43.         RealGripe( "\pNo more services may be added" );
  44.         return noErr;
  45.     }
  46.  
  47.     /* Look for a currently running speller */
  48.  
  49.     err = GetSpellerAddress( &spellerAddr );
  50.     if ( err ){
  51.         return ( err == userCanceledErr ? noErr : err );
  52.     }
  53.  
  54.     /*****
  55.      * Request the speller's batch menu string
  56.      *****/
  57.     
  58.     err = GetAppProperty( &spellerAddr, pBatchMenuString, typePString, &stringDesc );
  59.     if ( err ){
  60.         Gripe( "\pGetAppProperty failed to get menu string" );
  61.         return err;
  62.     }
  63.     
  64.     /*DebugStr( *(stringDesc.dataHandle) );*/    /* Uncomment this to look at string */
  65.     
  66.     
  67.     /*****
  68.      * Request the speller's location alias
  69.      *****/
  70.  
  71.     err = GetAppProperty( &spellerAddr, pLocation, typeAlias, &aliasDesc );
  72.     if ( err ){
  73.         Gripe( "\pGetAppProperty failed to get location alias" );
  74.         return err;
  75.     }
  76.     
  77.     /* Save the information in the preferences file */
  78.     
  79.     err = SaveServiceInfo( kBatchService, stringDesc, aliasDesc );
  80.     if ( err ){
  81.         Gripe( "\pCould not save service info" );
  82.         return err;
  83.     }
  84.     
  85.     RebuildServiceMenu();
  86.     
  87.     err = AEDisposeDesc( &stringDesc );
  88.     if ( err ){
  89.         Gripe( "\pAEDisposeDesc failed" );
  90.         return err;
  91.     }
  92.  
  93.     err = AEDisposeDesc( &aliasDesc );
  94.     if ( err ){
  95.         Gripe( "\pAEDisposeDesc failed" );
  96.         return err;
  97.     }
  98.  
  99.     err = AEDisposeDesc( &spellerAddr );
  100.     if ( err ){
  101.         Gripe( "\pAEDisposeDesc failed" );
  102.         return err;
  103.     }
  104.     spellerAddr.descriptorType = typeNull;
  105.     spellerAddr.dataHandle = (Handle)NULL;
  106.  
  107.     return noErr;
  108. }
  109.  
  110. OSErr GetAppProperty( AEAddressDesc *spellerAddrPtr,
  111.                         DescType propCode,
  112.                         DescType desiredType,
  113.                         AEDesc *resultPtr )
  114. {
  115.     AEDesc            errDesc;
  116.     AppleEvent        getDataEvent;
  117.     AppleEvent        replyEvent;
  118.     AEDesc            nullDesc;
  119.     AEDesc            propSpec;
  120.     AEDesc            propDesc;
  121.     OSErr            err;
  122.  
  123.     /* Create the descriptor for the container (the application, or null) */
  124.  
  125.     err = AECreateDesc( typeNull, (Ptr)NULL, (Size)0, &nullDesc );
  126.     if ( err )
  127.         return err;
  128.     
  129.     /* Create the key data, which gives the code for the desired property */
  130.  
  131.     err = AECreateDesc( typeType, (Ptr)&propCode, sizeof( propCode ), &propDesc );
  132.     if ( err )
  133.         return err;
  134.  
  135.     /* Create the Object Specifier for the menu string property */
  136.     
  137.     err = CreateObjSpecifier( typeProperty,
  138.                                 &nullDesc,
  139.                                 formPropertyID,
  140.                                 &propDesc,
  141.                                 true,                    /* Dispose of input descriptors */
  142.                                 &propSpec );
  143.     if ( err )
  144.         return err;
  145.  
  146.     /* Create the event to send to the speller */
  147.     
  148.     err = AECreateAppleEvent( kAECoreSuite,
  149.                                 kAEGetData,
  150.                                 spellerAddrPtr,
  151.                                 kAutoGenerateReturnID,
  152.                                 kAnyTransactionID,
  153.                                 &getDataEvent );
  154.     
  155.     if ( err ){
  156.         Gripe( "\pcreate getd event failed" );
  157.         return err;
  158.     }
  159.     
  160.     /* Insert the object specifier as the direct object of the batch event */
  161.  
  162.     err = AEPutParamDesc( &getDataEvent,
  163.                             keyDirectObject,
  164.                             &propSpec );
  165.     if ( err ){
  166.         Gripe( "\pAEPutParamDesc failed to put direct object on Get Data event" );
  167.         return err;
  168.     }
  169.     err = AEDisposeDesc( &propSpec );
  170.     if ( err ){
  171.         Gripe( "\pAEDisposeDesc failed" );
  172.         return err;
  173.     }
  174.  
  175.     /* Send the event.  We await the reply, so that if there is a failure of some
  176.      * sort in the initial connection, we can alert the user right away.  The timeout
  177.      * value to use here should be as long as one would care to have a user wait for
  178.      * the completion of a menu command.  Since we expect that the speller is on a local
  179.      * machine in this case, and should be able to respond immediately, we just give
  180.      * a few seconds for the timeout.
  181.      *
  182.      * We should assign an idle proc to spin the cursor.  Even better would be a progress
  183.      * dialog that says "Contacting speller" or some such, with an animated display that
  184.      * shows the time elapsed relative to the total timeout, so the user will know how
  185.      * long she may have to wait
  186.      */
  187.  
  188. #define kFewSeconds 300
  189.     
  190.     err = AESend( &getDataEvent,
  191.                     &replyEvent,
  192.                     kAEWaitReply + kAENeverInteract,
  193.                     kAENormalPriority,
  194.                     kFewSeconds,
  195.                     (IdleProcPtr)NULL,
  196.                     (EventFilterProcPtr)NULL );
  197.     
  198.     if ( err ){
  199.         Gripe( "\psend getd event failed" );
  200.         return err;
  201.     }
  202.     err = AEDisposeDesc( &getDataEvent );
  203.     if ( err ){
  204.         Gripe( "\pAEDisposeDesc failed" );
  205.         return err;
  206.     }
  207.  
  208.     /* At this point we have received the client's reply event.  Check for an error
  209.      * result.
  210.      */
  211.     
  212.     err = AEGetParamDesc( &replyEvent,
  213.                             keyErrorNumber,
  214.                             typeShortInteger,
  215.                             &errDesc );
  216.  
  217.     if ( err == errAEDescNotFound ){
  218.         /* There is no error value - get the data from the reply event.
  219.          * This will call our coercion routine to convert the text to a Pascal string -
  220.          * the data is actually either typeIntlText or typeChar.
  221.          */
  222.  
  223.         err = AEGetParamDesc( &replyEvent,
  224.                                 keyDirectObject,
  225.                                 desiredType,
  226.                                 resultPtr );
  227.         if ( err ){
  228.             DebugStr( "\pCannot get reply value" );
  229.             return err;
  230.         }        
  231.     
  232.     } else {
  233.         err = AEDisposeDesc( &replyEvent );
  234.         if ( err ){
  235.             DebugStr( "\pAEDisposeDesc failed" );
  236.             return;
  237.         }
  238.     
  239.         if ( err ){
  240.             /* There was an error in getting the descriptor */
  241.             return err;
  242.         }                    
  243.         
  244.         err = **(short**)(errDesc.dataHandle);
  245.         /* err = */ AEDisposeDesc( &propSpec );
  246.     
  247.         if ( err ){
  248.             DebugStr( "\pError result returned from speller" );
  249.             return err;
  250.         }
  251.     }
  252.  
  253.     return noErr;
  254. }
  255. void RebuildServiceMenu( void )
  256. {
  257.     MenuHandle        servMenu;
  258.     short            numItems;
  259.     short            i;
  260.     
  261.     servMenu = GetServiceMenu();
  262.     if ( !servMenu ){
  263.         Gripe( "\pCannot get service menu handle" );
  264.         return;
  265.     }
  266.     
  267.     numItems = CountMItems( servMenu );
  268.     
  269.     for ( i = numItems; i > kSMDash; i-- ){
  270.         DelMenuItem( servMenu, i );
  271.     }
  272.     
  273.     BuildServiceMenu();
  274.     
  275.     return;
  276. }
  277.  
  278. OSErr GetSpellerAddress( AEAddressDesc    *spellerAddrPtr )
  279. {
  280.     PortInfoRec portInfo;
  281.     TargetID    targetID;
  282.     OSErr        err;
  283.     AEAddressDesc    spellerAddr;
  284.  
  285.     err = GetTargetAddress( (StringPtr)"\pChoose a Word Services Server",
  286.                             (StringPtr)"\pApple Event Aware Programs",
  287.                             &portInfo,
  288.                             spellerAddrPtr,
  289.                             (StringPtr)"\pWORDSERVICES",
  290.                             &targetID );
  291.     return err;
  292. }
  293.  
  294. short CountServices( void )
  295. {
  296.     WWJrPrefsHdl    prefHdl;
  297.     short            i;
  298.     short            count;
  299.     
  300.     prefHdl = GetPrefHandle();
  301.     if ( !prefHdl ){
  302.         Gripe( "\pCannot get preferences handle" );
  303.         return kMaxServices;
  304.     }
  305.  
  306.     count = 0;
  307.     
  308.     for ( i = 0; i < kMaxServices; i++ ){
  309.         if ( (*prefHdl)->serviceType[ i ] != kNoService )
  310.             count++;
  311.     }
  312.     
  313.     return count;
  314. }
  315.  
  316. short GetServiceSlot( void )
  317. {
  318.     WWJrPrefsHdl    prefHdl;
  319.     short            i;
  320.     
  321.     prefHdl = GetPrefHandle();
  322.     if ( !prefHdl ){
  323.         Gripe( "\pCannot get preferences handle" );
  324.         return kMaxServices;
  325.     }
  326.     
  327.     for ( i = 0; i < kMaxServices; i++ ){
  328.         if ( (*prefHdl)->serviceType[ i ] == kNoService )
  329.             return i;
  330.     }
  331.     
  332.     return kMaxServices;            /* No Free slots */
  333. }
  334.  
  335. OSErr SaveServiceInfo( ServiceType serviceType, AEDesc menuDesc, AEDesc aliasDesc )
  336. {
  337.     short            slot;
  338.     WWJrPrefsHdl    prefHdl;
  339.     short            resID;
  340.     Handle            resHandle;
  341.     short            curFile;
  342.     OSErr            err;
  343.  
  344.     slot = GetServiceSlot();
  345.     
  346.     if ( slot == kMaxServices ){
  347.         Gripe( "\pOut of slots for new services" );
  348.         return ioErr;                                /* Not sure what a good error would be */
  349.     }
  350.     
  351.     prefHdl = GetPrefHandle();
  352.     if ( !prefHdl ){
  353.         Gripe( "\pCannot get preferences handle" );
  354.         return resNotFound;
  355.     }
  356.  
  357.     resID = kServiceBaseID + slot;
  358.     
  359.     curFile = CurResFile();
  360.     UseResFile( gPrefFileRefNum );
  361.     
  362.     /* Make sure there's no old resources around... there shouldn't be */
  363.  
  364.     resHandle = GetResource( 'STR ', resID );
  365.     if ( resHandle )
  366.         RmveResource( resHandle );
  367.  
  368.     resHandle = GetResource( 'ALis', resID );
  369.     if ( resHandle )
  370.         RmveResource( resHandle );
  371.     
  372.     /* Copy the string into the resource file */
  373.     
  374.     resHandle = menuDesc.dataHandle;
  375.     
  376.     err = HandToHand( &resHandle );
  377.     if ( err ){
  378.         UseResFile( curFile );
  379.         return err;
  380.     }
  381.     
  382.     AddResource( resHandle, 'STR ', resID, "\p" );
  383.     err = ResError();
  384.     if ( err ){
  385.         DisposHandle( resHandle );
  386.         UseResFile( curFile );
  387.         return err;
  388.     }
  389.     WriteResource( resHandle );
  390.     
  391.     /* Copy the alias record into the resource file */
  392.     
  393.     resHandle = aliasDesc.dataHandle;
  394.     
  395.     err = HandToHand( &resHandle );
  396.     if ( err ){
  397.         UseResFile( curFile );
  398.         return err;
  399.     }
  400.     
  401.     AddResource( resHandle, rAliasType, resID, "\p" );    /* rAliasType is 'alis' */
  402.     err = ResError();
  403.     if ( err ){
  404.         DisposHandle( resHandle );
  405.         UseResFile( curFile );
  406.         return err;
  407.     }
  408.     WriteResource( resHandle );
  409.     
  410.     (*prefHdl)->serviceType[ slot ] = serviceType;
  411.     
  412.     ChangedResource( prefHdl );
  413.     WriteResource( prefHdl );
  414.     
  415.     UseResFile( curFile );
  416.  
  417.     return noErr;
  418. }